package evolution;
/*
 * Created on 14 nov. 2007
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */

/**
 * @author nancel
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class Perceptator {
	
	int nb_entrees;
	int nb_couche;
	int nb_sorties;
	
	int indice_biais;
	
	double[] entree;
	double[] couche;
	double[] sortie;
	
	double[][] poids_entree_couche;
	double[][] poids_couche_sortie;
	
	Perceptator(int entr, int couch , int sort, double[] poids){
		nb_entrees = entr+1;
		nb_couche = couch;
		nb_sorties = sort;
		
		indice_biais = entr;
		
		entree = new double[nb_entrees];
		couche = new double[nb_couche];
		sortie = new double[nb_sorties];
		
		poids_entree_couche = new double[nb_entrees][nb_couche];
		poids_couche_sortie = new double[nb_couche][nb_sorties];
		
		setPoids(poids);

	}
	
	Perceptator(int entr, int couch , int sort){
		this(entr, couch, sort, null); 
	}
	
	double activation(double e){
		
		return Math.tanh(e);
		
	}
	
	double[] pas_optimisation(){
		
		double poids;
		
		// couche
		for (int c = 0; c < nb_couche; c++){
			
			poids = 0;
		
			for (int j = 0; j < nb_entrees; j++)
				poids += poids_entree_couche[j][c] * entree[j];
			
			couche[c] = activation(poids);
		}
		
		 // print_noeuds(couche);
		
		// sortie
		for (int s = 0; s < nb_sorties; s++){
			
			poids = 0;
		
			for (int j = 0; j < nb_couche; j++)
				poids += poids_couche_sortie[j][s] * couche[j];
			
			sortie[s] = poids;
		}
		
		 // System.out.println("Etape d'optimisation - Sorties : ");
		 // print_noeuds(sortie);
		
		return sortie;
		
	}
	
	double[] run(double[] param_entrees, boolean last){
		
		for (int e = 0; e < nb_entrees; e++){
			if (e < nb_entrees-1)
				entree[e] = param_entrees[e];
		}
		entree[indice_biais] = 1;
		
		for (int c = 0; c < nb_couche; c++){	
			couche[c] = 0;	
		}
		
		for (int s = 0; s < nb_sorties; s++){
			sortie[s] = 0;
		}
		
//		System.out.println("Entr?es : ");
//		print_noeuds(param_entrees);
//		System.out.println(nb_couche + " couches, " + nb_sorties + " sorties");
//		System.out.println("Poids entree-couche : ");
//		print_poids(poids_entree_couche);
//		System.out.println("Poids couche-sortie : ");
//		print_poids(poids_couche_sortie);
		
		double res[] = pas_optimisation();
		
		if (last){
			System.out.println("\tCouche :");
			print_noeuds(couche);
			System.out.println("\tSortie :");
			print_noeuds(sortie);
		}
		
		return res;
		
		
	}
	
	void print_noeuds(double[] tab){
		
		System.out.print("[ ");
		for (int i = 0; i < tab.length; i++)
			System.out.print(tab[i] + " ");
		System.out.println("]");
		
	}
	
	void print_poids(double[][] tab){
		
		System.out.print("\t");
		
		for (int i = 0; i < tab.length; i++)
			System.out.print(i + "\t");
		
		System.out.println();
		
		for (int i = 0; i < tab[0].length; i++){
			System.out.print(i + "\t");
			
			for (int j = 0; j < tab.length; j++)
				System.out.print(tab[j][i] + "\t");
			System.out.println();
		}
		
	}
	
	double trunc(double e){
		
		e *= 100;
		
		e = (double)Math.round(e);
		
		e /= 100;
		
		return e;
		
	}
	
	public void setPoids(double[] poids){
		if (poids != null){
			for (int c = 0; c < nb_couche; c++){
				couche[c] = 0;
				for (int e = 0; e < nb_entrees; e++){
					poids_entree_couche[e][c] = poids[e * nb_couche + c] ;
				}
				entree[indice_biais] = 1;
				for (int s = 0; s < nb_sorties; s++){
					poids_couche_sortie[c][s] = poids[nb_entrees*nb_couche +c * nb_sorties + s] ;
				}
			}
		}else{
			for (int c = 0; c < nb_couche; c++){	
				couche[c] = 0;
				for (int e = 0; e < nb_entrees; e++){
					poids_entree_couche[e][c] = Math.random() ;
				}
				entree[indice_biais] = 1;
				for (int s = 0; s < nb_sorties; s++){
					poids_couche_sortie[c][s] = Math.random() ;
				}
			}
		}
	}
	
}
